package hn.sigit.dao.hnd.ladmshadow;

import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.hibernatespatial.criterion.SpatialRestrictions;

import com.vividsolutions.jts.geom.Polygon;

import hn.sigit.model.hnd.ladmshadow.Parcel;
import hn.sigit.dao.SigitDAO;


public class ParcelDAO extends SigitDAO<Parcel> {
	private static final long serialVersionUID = 1L;
	private static final String maxTimeStampHQL = "SELECT MAX(beginLifespanVersion) FROM Parcel WHERE presentationId = :presentationId";
	private static final String minTimeStampHQL = "SELECT MIN(beginLifespanVersion) FROM Parcel WHERE presentationId = :presentationId";
	private static final String deleteParcelsHQL = "DELETE FROM Parcel WHERE presentationId = :presentationId";
	private static final String deleteParcelsHQL2 = "DELETE FROM Parcel WHERE presentationId = :presentationId AND snapshot = :snapshot";

	protected ParcelDAO() {
	}

	public static Parcel loadParcelById(long suId) {
		return loadParcelById(getSession(), suId);
	}
	public static List<Parcel> loadParcelsByPresentationId(long presentationId) {
		return loadParcelsByPresentationId(getSession(), presentationId);
	}
	public static List<Parcel> loadBeforeParcelsByPresentationId(long presentationId) {
		return loadBeforeParcelsByPresentationId(getSession(), presentationId);
	}
	public static List<Parcel> loadRequestedParcelsByPresentationId(long presentationId) {
		return loadRequestedParcelsByPresentationId(getSession(), presentationId);
	}
	public static List<Parcel> loadNeighborParcelsByPresentationId(long presentationId) {
		return loadNeighborParcelsByPresentationId(getSession(), presentationId);
	}
	public static List<Parcel> loadParcelByPresentationIdAndLadmId(long presentationId, long ladmId) {
		return loadParcelByPresentationIdAndLadmId(getSession(), presentationId, ladmId);
	}
	public static List<Parcel> loadNeighborsByParcel(Parcel parcel) {
		return loadNeighborsByParcel(getSession(), parcel);
	}
	public static List<Parcel> loadParcelsByBeginLifespanVersion(Date beginLifespanVersion) {
		return loadParcelsByBeginLifespanVersion(getSession(), beginLifespanVersion);
	}
	public static List<Parcel> loadParcelsByEndLifespanVersion(Date endLifespanVersion) {
		return loadParcelsByEndLifespanVersion(getSession(), endLifespanVersion);
	}
	public static List<Parcel> loadOriginalParcelsByPresentationId(long presentationId) {
		return loadOriginalParcelsByPresentationId(getSession(), presentationId);
	}
	public static List<Parcel> loadFinalParcelsByPresentationId(long presentationId) {
		return loadFinalParcelsByPresentationId(getSession(), presentationId);
	}
	public static List<Parcel> loadParcelsBeforeTransactionByPresentationId(Long presentationId) {
		return loadParcelsBeforeTransactionByPresentationId(getSession(), presentationId);
	}
	public static List<Parcel> loadParcelsAfterTransactionByPresentationId(Long presentationId) {
		return loadParcelsAfterTransactionByPresentationId(getSession(), presentationId);
	}
	public static Parcel loadParcelAfterTransactionByPresentationIdAndSuID(Long presentationId, Long suID) {
		return loadParcelAfterTransactionByPresentationIdAndSuID(getSession(), presentationId, suID);
	}
	
	public static Date loadMaxTimeStamp(long presentationId) {
		return loadMaxTimeStamp(getSession(), presentationId);
	}
	public static Date loadMinTimeStamp(long presentationId) {
		return loadMinTimeStamp(getSession(), presentationId);
	}
	public static int deleteParcelsByPresentationId(long presentationId, boolean includeSnapshot) {
		return deleteParcelsByPresentationId(getSession(), presentationId, includeSnapshot);
	}
	public static int clearParcelsAssociationsByPresentationId(long presentationId, boolean includeSnapshot) {
		return clearParcelsAssociationsByPresentationId(getSession(), presentationId, includeSnapshot);
	}
	
	
	public static Parcel loadParcelById(Session session, long suId) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("suID", suId));
		
		return (Parcel) criteria.uniqueResult();
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadParcelsByPresentationId(Session session, long presentationId) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("presentationId", presentationId));
		criteria.add(Restrictions.eq("snapshot", false));
		
		return (List<Parcel>) criteria.list();
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadBeforeParcelsByPresentationId(Session session, long presentationId) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("presentationId", presentationId));
		criteria.add(Restrictions.eq("readOnly", false));
		criteria.add(Restrictions.eq("snapshot", true));
		
		return (List<Parcel>) criteria.list();
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadRequestedParcelsByPresentationId(Session session, long presentationId) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("presentationId", presentationId));
		criteria.add(Restrictions.eq("readOnly", false));
		criteria.add(Restrictions.eq("snapshot", false));
		criteria.add(Restrictions.isNull("endLifespanVersion"));
		
		return (List<Parcel>) criteria.list();
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadNeighborParcelsByPresentationId(Session session, long presentationId) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("presentationId", presentationId));
		criteria.add(Restrictions.eq("readOnly", true));
		criteria.add(Restrictions.eq("snapshot", false));
		criteria.add(Restrictions.isNull("endLifespanVersion"));
		
		return (List<Parcel>) criteria.list();
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadParcelByPresentationIdAndLadmId(Session session, long presentationId, long ladmId) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("presentationId", presentationId));
		criteria.add(Restrictions.eq("ladmId", ladmId));
		
		return (List<Parcel>) criteria.list();
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadNeighborsByParcel(Session session, Parcel parcel) {
		Polygon filter = parcel.getShape();
		
		if (filter != null) {
			//Set<Parcel> parcelSet = new HashSet<Parcel>();
			
			Criteria criteria = session.createCriteria(Parcel.class);
			criteria.add(Restrictions.eq("snapshot", false));
			criteria.add(SpatialRestrictions.touches("shape", filter));
			
			return (List<Parcel>)criteria.list();
			/*
			@SuppressWarnings("unchecked")
			List<Parcel> touchingParcelList = (List<Parcel>)criteria.list();
			if (touchingParcelList != null)
				for (Parcel touchingP : touchingParcelList)
					if (touchingP.getShape().intersection(filter).getLength() > 0.0001)
						parcelSet.add(touchingP);
			
			return parcelSet;
			*/
		}
		
		return null;
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadParcelsByBeginLifespanVersion(Session session, Date beginLifespanVersion) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("snapshot", false));
		criteria.add(Restrictions.eq("beginLifespanVersion", beginLifespanVersion));
		
		return (List<Parcel>) criteria.list();
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadParcelsByEndLifespanVersion(Session session, Date endLifespanVersion) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("snapshot", false));
		criteria.add(Restrictions.eq("endLifespanVersion", endLifespanVersion));
		
		return (List<Parcel>) criteria.list();
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadOriginalParcelsByPresentationId(Session session, long presentationId) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("presentationId", presentationId));
		criteria.add(Restrictions.eq("modified", true));
		criteria.add(Restrictions.eq("snapshot", false));
		criteria.add(Restrictions.eq("original", true));
		
		return (List<Parcel>) criteria.list();
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadFinalParcelsByPresentationId(Session session, long presentationId) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("presentationId", presentationId));
		
		criteria.add(Restrictions.isNull("endLifespanVersion"));
		criteria.add(Restrictions.eq("snapshot", false));
		/*
		criteria.add(
				Restrictions.or(
						Restrictions.and(
								Restrictions.eq("modified", false),
								Restrictions.eq("original", false)),
						Restrictions.eq("modified", true)
				)
		);
		*/
		
		return (List<Parcel>) criteria.list();
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadParcelsBeforeTransactionByPresentationId(Session session, Long presentationId) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("presentationId", presentationId));
		criteria.add(Restrictions.eq("readOnly", false));
		criteria.add(Restrictions.eq("snapshot", true));
		
		return (List<Parcel>) criteria.list();
	}
	@SuppressWarnings("unchecked")
	public static List<Parcel> loadParcelsAfterTransactionByPresentationId(Session session, Long presentationId) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("presentationId", presentationId));
		criteria.add(Restrictions.eq("readOnly", false));
		criteria.add(Restrictions.eq("snapshot", false));
		criteria.add(Restrictions.isNull("endLifespanVersion"));
		
		return (List<Parcel>) criteria.list();
	}
	public static Parcel loadParcelAfterTransactionByPresentationIdAndSuID(Session session, Long presentationId, Long suID) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("presentationId", presentationId));
		criteria.add(Restrictions.eq("suID", suID));
		criteria.add(Restrictions.eq("readOnly", false));
		criteria.add(Restrictions.eq("snapshot", false));
		criteria.add(Restrictions.isNull("endLifespanVersion"));
		
		return (Parcel) criteria.uniqueResult();
	}
	
	
	
	
	public static Date loadMaxTimeStamp(Session session, long presentationId) {
		return (Date) session.createQuery(maxTimeStampHQL)
			.setLong("presentationId", presentationId)
			.uniqueResult();
	}
	public static Date loadMinTimeStamp(Session session, long presentationId) {
		return (Date) session.createQuery(minTimeStampHQL)
			.setLong("presentationId", presentationId)
			.uniqueResult();
	}
	public static int deleteParcelsByPresentationId(Session session, long presentationId, boolean includeSnapshot) {
		/*
		List<Parcel> parcels = loadParcelsByPresentationId(presentationId);

		Set<SpatialUnit> suSet;
		Property prop;
		
		for (Parcel p : parcels) {
			prop = p.getProperty();
			if (prop != null) {
				suSet = prop.getSpatialUnits();
				if (suSet != null)
					suSet.clear();
				PropertyDAO.save(prop);
				p.setBaunits(null);
			}
			delete(p);
		}
		*/

		if (includeSnapshot) {
			return session.createQuery(deleteParcelsHQL)
				.setLong("presentationId", presentationId)
				.executeUpdate();
		}
		return session.createQuery(deleteParcelsHQL2)
			.setLong("presentationId", presentationId)
			.setBoolean("snapshot", includeSnapshot)
			.executeUpdate();
		
		//return 0;
	}
	
	public static int clearParcelsAssociationsByPresentationId(Session session, long presentationId, boolean includeSnapshot) {
		Criteria criteria = session.createCriteria(Parcel.class);
		criteria.add(Restrictions.eq("presentationId", presentationId));
		if (!includeSnapshot)
			criteria.add(Restrictions.eq("snapshot", false));
		
		ScrollableResults parcelCursor = criteria.scroll();
		
		Parcel parcel;
		int count = 0;
		while (parcelCursor.next()) {
			parcel = (Parcel) parcelCursor.get(0);
			
			parcel.setPointOfReference(null);
			parcel.setBaunits(null);
			parcel.setElement(null);
			parcel.setWhole(null);
			parcel.setSpatialSources(null);
			parcel.setRelSpatialUnits1requiredrelationshipspatialunits(null);
			parcel.setRelSpatialUnits2requiredrelationshipspatialunits(null);
			parcel.setBfsMinus(null);
			parcel.setBfsPlus(null);
			parcel.setBfMinus(null);
			parcel.setBfPlus(null);
			
			if (++count % 100 == 0) {
				session.flush();
				session.clear();
			}
		}
		
		parcelCursor.close();
		
		return count;
	}

}
